package com.zff.rental.utils.collectors;


import com.zff.rental.vo.apartment.room.RoomVo;

import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 集合操作工具类
 *
 * @author HCY
 */
public class CollectionsUtils {
    /**
     * 合并两个集合
     */
    public static <T, C extends Collection<T>> C merge(Collection<T> collection1, Collection<T> collection2, Supplier<C> supplier) {
        C collection = supplier.get();
        if (collection1 != null && !collection1.isEmpty()) {
            collection.addAll(collection1);
        }

        if (collection2 != null && !collection2.isEmpty()) {
            collection.addAll(collection2);
        }
        return collection;
    }

    public static <T> List<T> mergeToList(Collection<T> collection1, Collection<T> collection2) {
        return merge(collection1, collection2, ArrayList::new);
    }

    public static <T> HashSet<T> mergeToSet(Collection<T> collection1, Collection<T> collection2) {
        return merge(collection1, collection2, HashSet::new);
    }

    /**
     * 减少集合的元素（不改变原来集合）
     */
    public static <T, M, C extends Collection<T>> C reduceBy(Collection<T> collection1, Collection<T> collection2, Function<T, M> map, Supplier<C> supplier) {
        if (collection1 == null || collection1.isEmpty()) {
            return supplier.get();
        }
        if (collection2 == null || collection2.isEmpty()) {
            C ts = supplier.get();
            ts.addAll(collection1);
            return ts;
        }
        Set<M> reduceSet = collection2.stream().map(map).collect(Collectors.toSet());
        return collection1.stream().filter(t -> !reduceSet.contains(map.apply(t))).collect(Collectors.toCollection(supplier));
    }

    /**
     * 减少集合的元素
     *
     * @param collection1 集合1
     * @param collection2 集合2
     */
    public static <T> List<T> reduceToList(Collection<T> collection1, Collection<T> collection2) {
        return reduceBy(collection1, collection2, t -> t, ArrayList::new);
    }

    /**
     * 根据元素映射，减少集合的元素
     *
     * @param collection1 集合1
     * @param collection2 集合2
     * @param map         根据元素映射
     */
    public static <T, M> List<T> reduceToList(Collection<T> collection1, Collection<T> collection2, Function<T, M> map) {
        return reduceBy(collection1, collection2, map, ArrayList::new);
    }

    /**
     * 减少集合的元素
     *
     * @param collection1 集合1
     * @param collection2 集合2
     */
    public static <T> Set<T> reduceToSet(Collection<T> collection1, Collection<T> collection2) {
        return reduceBy(collection1, collection2, t -> t, HashSet::new);
    }

    /**
     * 根据元素映射，减少集合的元素
     *
     * @param collection1 集合1
     * @param collection2 集合2
     * @param map         根据元素映射
     */
    public static <T, M> Set<T> reduceToSet(Collection<T> collection1, Collection<T> collection2, Function<T, M> map) {
        return reduceBy(collection1, collection2, map, HashSet::new);
    }

    /**
     * 取俩个集合的交集（取集合1的元素）
     */
    public static <T, M, C extends Collection<T>> C intersection(Collection<T> collection1, Collection<T> collection2, Function<T, M> map, Supplier<C> supplier) {
        if (collection1 == null || collection1.isEmpty()) {
            return supplier.get();
        }
        if (collection2 == null || collection2.isEmpty()) {
            return supplier.get();
        }

        Set<M> reduceSet = collection2.stream().map(map).collect(Collectors.toSet());
        return
                // 根据map去除集合1中的重复元素
                collection1.stream().collect(Collectors.toMap(map, t -> t, (t1, t2) -> t1))
                        .values()
                        // 根据map取集合2中的重复元素（交集）
                        .stream().filter(t -> reduceSet.contains(map.apply(t)))
                        .collect(Collectors.toCollection(supplier));
    }

    public static <T> List<T> intersectionToList(Collection<T> collection1, Collection<T> collection2) {
        return intersection(collection1, collection2, t -> t, ArrayList::new);
    }

    public static <T, M> List<T> intersectionToList(Collection<T> collection1, Collection<T> collection2, Function<T, M> map) {
        return intersection(collection1, collection2, map, ArrayList::new);
    }

    /**
     * 获取集合大小，如果集合为空，则返回0
     */
    public static long getSizeOrZero(List<RoomVo> list) {
        return list == null ? 0 : list.size();
    }
}
